The One Arm Expected Events calculator computes an estimate of the expected events for a planned one-arm study. The program assumes uniform accrual and exponential survival. It allows the user to specify a follow-up period after the close of study accrual. The program default presents a table of expected event totals at timepoints spanning the duration of the study. Alternatively, user can calculate the expected proportion of events at a given time, or the time at which a given proportion of events have occurred. The program will allow the user to specify a percentage of patients that have no risk (‘Percent cured’).
The user is prompted for values to the following items. For items that have initial default values set, the values are given in parentheses.
For calculations of expected events at given analysis time(s):
For calculations of analysis time for a given number of expected events:
Hazard rate: The hazard rate \(\lambda\) for a survival probability S(t) at time t is computed as follows:
\[ \lambda = \frac{-ln(S(t))}{t} \]
Total probability of event: The probability \(P_{tot}\) of an event for a study with hazard rate \(\lambda\), accrual time \(t_{acc}\), and follow-up time \(t_{fu}\), is as follows:
\[ P_{tot} = 1 - \frac{e^{-\lambda t_{fu}}(1-e^{-\lambda t_{acc}})}{\lambda t_{acc}} \]
Fraction of the total events at time t: At times before the completion of accrual, the probability of an event at analysis time t is
\[P(Event|t) =\frac{ P_{d}|t}{P_{tot}}\] At times before the completion of accrual, \(P_{d}|t\) is as follows:
\[ P_{d}|t = \frac{(\frac{1}{\lambda}e^{-\lambda t})+t-\frac{1}{\lambda}}{t_{acc}} \]
At all other times, \(P_{d}|t\) is as follows:
\[ P_{d}|t = 1 - \frac{e^{-\lambda (t-t_{acc})}(1-e^{-\lambda t_{acc}})}{\lambda t_{acc}} \]
The program is written in R.
View Analysis Time for a Given Proportion of Total Events Code
function(hazard, medsurv, survtime, survprob, accrual_time, fu_time, N, pct_events, survival_input, pct_cured) {
if (survival_input == "Median Survival") {
hazard = -1 * log(0.5) / medsurv
}
if (survival_input == "Survival Probability") {
hazard = -1 * log(survprob) / survtime
}
perdeath = function(hazard, accrual_time, fu_tume, time) {
ptot = 1 - exp(-1 * hazard * fu_tume) * (1 - exp(-1 * hazard * accrual_time)) / (hazard * accrual_time)
if (time < accrual_time) {
pd = ((1 / hazard) * exp(-1 * hazard * time) + time - 1 / hazard) / accrual_time
}
else {
pd = 1 - exp(-1 * hazard * (time - accrual_time)) * (1 - exp(-1 * hazard * accrual_time)) / (hazard * accrual_time)
}
return(pd / ptot)
}
aperdeath = function(hazard, accrual, follow, p) {
v = .5
dv = .5
x = 0
while (dv > 1e-6) {
x = 1 / v - 1
dv = dv / 2
if (perdeath(hazard, accrual, follow, x) > p) {
v = v + dv
} else {
v = v - dv
}
}
return(x)
}
eea = (1 - pct_cured) * N * (1 - exp(-1 * hazard * fu_time) * (1 - exp(-1 * hazard * accrual_time)) / (hazard * accrual_time))
analysis_time = aperdeath(hazard, accrual_time, fu_time, pct_events)
eet = eea * perdeath(hazard, accrual_time, fu_time, analysis_time)
result = list(hazard = signif(hazard, 2),
analysis_time = round(analysis_time, 2),
eet = floor(eet),
eea = floor(eea))
return(jsonlite::toJSON(result, pretty = TRUE))
}
View Expected Events for Given Analysis Time Code
function(hazard, medsurv, survtime, survprob, accrual_time, fu_time, N, analysis_time, survival_input, pct_cured) {
if (survival_input == "Median Survival") {
hazard = -1 * log(0.5) / medsurv
}
if (survival_input == "Survival Probability") {
hazard = -1 * log(survprob) / survtime
}
perdeath = function(hazard, accrual_time, fu_tume, time) {
ptot = 1 - exp(-1 * hazard * fu_tume) * (1 - exp(-1 * hazard * accrual_time)) / (hazard * accrual_time)
if (time < accrual_time) {
pd = ((1 / hazard) * exp(-1 * hazard * time) + time - 1 / hazard) / accrual_time
} else {
pd = 1 - exp(-1 * hazard * (time - accrual_time)) * (1 - exp(-1 * hazard * accrual_time)) / (hazard * accrual_time)
}
return(pd / ptot)
}
pct_eet = perdeath(hazard, accrual_time, fu_time, analysis_time)
pct_eet_100 = pct_eet * 100
eea = (1 - pct_cured) * N * (1 - exp(-1 * hazard * fu_time) * (1 - exp(-1 * hazard * accrual_time)) / (hazard * accrual_time))
eet = pct_eet * eea
result = list(hazard = signif(hazard, 2),
pct_eet_100 = round(pct_eet_100, 1),
eet = floor(eet),
eea = floor(eea))
return(jsonlite::toJSON(result, pretty = TRUE))
}
View Expected Event Table Code
function(hazard, medsurv, survtime, survprob, accrual_time, fu_time, N, time_unit, survival_input, pct_cured) {
if (survival_input == "Median Survival") {
hazard = -1 * log(0.5) / medsurv
}
if (survival_input == "Survival Probability") {
hazard = -1 * log(survprob) / survtime
}
end_time = (accrual_time + fu_time) * (ifelse(time_unit == 'Years', 12, 1))
follow_time = (fu_time) * (ifelse(time_unit == 'Years', 12, 1))
acc_time = (accrual_time) * (ifelse(time_unit == 'Years', 12, 1))
hazard_months = hazard / ifelse(time_unit == 'Years', 12, 1)
bymonth = matrix(nrow = end_time, ncol = 5)
perdeath = function(hazard, accrual_time, fu_tume, time) {
ptot = 1 - exp(-1 * hazard * fu_tume) * (1 - exp(-1 * hazard * accrual_time)) / (hazard * accrual_time)
if (time < accrual_time) {
pd = ((1 / hazard) * exp(-1 * hazard * time) + time - 1 / hazard) / accrual_time
} else {
pd = 1 - exp(-1 * hazard * (time - accrual_time)) * (1 - exp(-1 * hazard * accrual_time)) / (hazard * accrual_time)
}
return(pd / ptot)
}
p_t = perdeath(hazard_months, acc_time, follow_time, end_time)
eea = (1 - pct_cured) * N * (1 - exp(-1 * hazard_months * follow_time) * (1 - exp(-1 * hazard_months * acc_time)) / (hazard_months * acc_time))
eet = p_t * eea
for (i in 1:end_time) {
Ni = floor(min(N, i * (N / acc_time)))
p_i = perdeath(hazard_months, acc_time, follow_time, i)
ee_i = eet * p_i
pct_i = ee_i / eet * 100
pct_accr = Ni * 100 / N
bymonth[i, ] = c(i, round(ee_i,1), round(pct_i,1), Ni, round(pct_accr,1))
}
bymonth = as.data.frame(bymonth)
names(bymonth) = c("TimeinMonths", "TotalEvents", "PercentTotalEvents", "TotalAccrual", "PercentAccrual")
bymonth$PercentTotalEvents = paste0(bymonth$PercentTotalEvents, "%")
bymonth$PercentAccrual = paste0(bymonth$PercentAccrual, "%")
result = list(hazard = signif(hazard, 2),
event_table = bymonth)
return(jsonlite::toJSON(result, pretty = TRUE))
}